#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
//#include <netdb.h>
#include <Includes.h>
#include <EC600S_AT/AT.h>
#include <DRV_EC600S.h>
#include <DRV_EC600S_Sock.h>
#include <OPP_Debug.h>

T_MUTEX tcpipMux;
EN_EC600S_CTX g_enCtxSt=CTX_INIT;
int g_iSockHasData[SOCK_MAX]={0};
int g_iSockDataSplit=0;//缓存模式下是否拆分套接字数据

int AtResponseQIOPEN(char *buffer, int len, unsigned char *exdata)
{
    //int ret;
    //int sock,err;

    if(NULL == strstr(buffer,"OK"))
    {
        return 1;
    }
    /*
    //+QIOPEN: 1,0
    ret=sscanf(buffer,"\r\n%*[^:]:%d,%d%*[\r\n]",&sock,&err);
    if(2!=ret)
    {
        return 2;
    }
    if(err!=0)
    {
        return err;
    }
    */

    return 0;
}

int AtResponseQISEND(char *buffer, int len, unsigned char *exdata)
{
    if(NULL == strstr(buffer,">"))
    {
        return 1;
    }
    return 0;
}

int AtResponseQISEND0(char *buffer, int len, unsigned char *exdata)
{
    ST_QISEND0 q;
    int ret;

    if(NULL == strstr(buffer,"OK"))
    {
        return 1;
    }
    ret=sscanf(buffer,"%*[^:]:%d,%d,%d%*[^\r\n]",&q.tsl,&q.ack,&q.unack);
    if(3!=ret)
    {
        return 2;
    }
    if(exdata!=NULL)
        memcpy(exdata,&q,sizeof(ST_QISEND0));
    return 0;
}

unsigned char *hexok(unsigned char *buffer, int len)
{
	int i;

	for(i=0;i<len-1;i++)
	{
		if(buffer[i]=='O'&&buffer[i+1]=='K')
		{
			return &buffer[i];
		}
	}
	return NULL;
}

int AtResponseQIRD(char *buffer, int len, unsigned char *exdata)
{
    int ret;
    char *ptr;
    int length;
    ST_QIRD *q=(ST_QIRD *)exdata;

    if(NULL == hexok((unsigned char*)buffer,len))
    {
        return 1;
    }

    ret=sscanf(buffer,"%*[^:]:%d%*[^\r\n]",&length);
    if(1!=ret)
    {
        return 2;
    }
    q->len=length;
    ptr = strstr(buffer+2,"\r\n");
    if(ptr)
    {
        //拷贝数据
        memcpy(q->data,ptr+2,length);
        Ec600sDataDump(q->data, length);
    }

    return 0;
}


int AtResponseQIRD0(char *buffer, int len, unsigned char *exdata)
{
    int ret;
    ST_QIRD0 *q=(ST_QIRD0 *)exdata;

    if(NULL == strstr(buffer,"OK"))
    {
        return 1;
    }

    ret=sscanf(buffer,"%*[^:]:%d,%d,%d%*[^\r\n]",&q->total_receive_length,&q->have_read_length,&q->unread_length);
    if(3!=ret)
    {
        return 2;
    }

    return 0;
}

int AtResponseQISENDDATA(char *buffer, int len, unsigned char *exdata)
{
    if(strstr(buffer,"SEND OK"))
    {
        return 0;
    }
    else if(strstr(buffer,"SEND FAIL"))
    {
        return 1;
    }
    else if(strstr(buffer,"ERROR"))
    {
        return 2;
    }
    return 0;
}

int AtResponseQISENDEX(char *buffer, int len, unsigned char *exdata)
{
    return AtResponseQISENDDATA(buffer,len,exdata);
}

int Ec600sPdpDeactAction()
{
    if(Ec600sStGet()>=EC600S_DEV_PWRON)
    {
        Ec600sCtxSet(CTX_INIT);
    }

    return 0;
}

//UNINET,CMNET,CTNET
ST_CMD ctxInitCmd[]={
    //{"AT_QICSGP","AT+QICSGP=1,1,\"CMNET\",\"\",\"\",1\r",300,NULL,NULL},
    {"AT_QICSGP","AT+QICSGP=%d,1,\"%s\",\"\",\"\",1\r",300,NULL,NULL,NULL},
};

ST_CMD qiactCmd[]={
    {"AT_QIACT","AT+QIACT=%d\r",150000,AtResponseComm,NULL,NULL},
};

ST_CMD qideactCmd[]={
    {"AT_QIDEACT","AT+QIDEACT=%d\r",40000,AtResponseComm,NULL,Ec600sPdpDeactAction},
};


ST_CMD sockCmd[]={
    {"AT_QIOPEN","AT+QIOPEN=1,%d,\"%s\",\"%s\",%d,%d,1\r",150000,AtResponseQIOPEN,NULL,NULL},
    //{"AT_QIOPEN","AT+QIOPEN=1,0,\"TCP\",\"103.46.128.49\,21277,0,1\r",300,NULL,NULL},
};


ST_CMD closeCmd[]={
    {"AT_QICLOSE","AT+QICLOSE=%d,%d\r",10000,NULL,NULL,NULL},
};

ST_CMD sendCmd[]={
    {"AT_QISEND","AT+QISEND=%d,%d\r",5000/*300*/,AtResponseQISEND,NULL,NULL},
};

ST_CMD dataCmd[]={
    {"AT_DATA","%s\r",300,AtResponseQISENDDATA,NULL,NULL},
};

//发送16进制数据
ST_CMD sendexCmd[]={
    {"AT_QISENDEX","AT+QISENDEX=%d,\"%s\"\r",300,AtResponseQISENDEX,NULL,NULL},
};

//查询已发送字节数
ST_CMD send0Cmd[]={
    {"AT_QISEND","AT+QISEND=%d,0\r",300,AtResponseQISEND0,NULL,NULL},
};

ST_CMD ctrlZCmd[]={
    {"CTRL_Z","\032\r",300,AtResponseComm,NULL,NULL},
};

//查询缓存数据
ST_CMD qird0Cmd[]={
    {"AT_QIRD0","AT+QIRD=%d,0\r",300,AtResponseQIRD0,NULL,NULL},
};


ST_CMD qirdCmd[]={
    {"AT_QIRD","AT+QIRD=%d,1500\r",300,AtResponseQIRD,NULL,NULL},
};


/**
@brief TCPIP场景初始化
@param
@return 0成功,非0失败
**/
int Ec600sCtxInit()
{
    ST_COPS c;
    char buf[32]={0};

    if(0==Ec600sAT_COPS((char *)&c))
    {
        if(strstr(c.oper,"CT"))
            strcpy(buf,"CTNET");
        else if(strstr(c.oper,"MOBILE"))
            strcpy(buf,"CMNET");
        else if(strstr(c.oper,"UNICOM"))
            strcpy(buf,"UNINET");
        else
            strcpy(buf,"CMNET");
        return Ec600sAtFmtCmdOne(&ctxInitCmd[0], NULL, ATCMD_LEN, CTX_DEF, buf);
    }
    return 1;
}

/**
@brief 场景激活
@param ctx 场景号
@return 0激活成功,-1写失败,-2命令执行超时,-99激活失败
**/
int Ec600sAT_QIACT(int ctx)
{
    return Ec600sAtFmtCmdOne(&qiactCmd[0], NULL, ATCMD_LEN, ctx);
}

/**
@brief 场景去激活
@param ctx 场景号
@return 0去激活成功,-1写失败,-2命令执行超时,-99去激活失败
**/
int Ec600sAT_QIDEACT(int ctx)
{
    return Ec600sAtFmtCmdOne(&qideactCmd[0], NULL, ATCMD_LEN, ctx);
}

/**
@brief TCPIP QIOPEN操作函数
@param sock 套接字
@param sock_type 套接字类型
@param to_addr 目的地址
@param local_addr 本地地址
@return
**/
int Ec600sAT_QIOPEN(int sock,EN_SOCK_TYPE sock_type,EC600S_ADDR *to_addr,EC600S_ADDR *local_addr)
{
    char proto[4]={0};
    int ret;

    if(SOCK_TCP==sock_type)
    {
        strcpy(proto,"TCP");
    }
    else if(SOCK_UDP==sock_type)
    {
        strcpy(proto,"UDP");
    }
    else
    {
        return 1;
    }

    ret=Ec600sAtFmtCmdOne(&sockCmd[0], NULL, ATCMD_LEN, sock,proto,to_addr->dstAddr,to_addr->port,local_addr->port);
    if(ret==0)
        Ec600sQIOPENTo(sock,1);
    return ret;
}

/**
@brief TCPIP QICLOSE操作函数
@param sock 套接字
@return
**/
int Ec600sAT_QICLOSE(int sock)
{
    int ret = Ec600sAtFmtCmdOne(&closeCmd[0], NULL, ATCMD_LEN, sock, QICLOSETO);
    if(ret!=0)
        Ec600sReset(EC600S_RST_CMD);
    return ret;
}

/**
@brief TCPIP QISEND操作函数
@param sock 套接字
@param len 数据长度
@return
**/
int Ec600sAT_QISEND(int sock,int len)
{
    static int ret=0;
    U32 tick_start=0;
    char outbuf[NEUL_MAX_BUF_SIZE] = {0};

    //上次发送失败先发送ctrl+z
    if(ret!=0)
    {
        ret=Ec600sAtCmdOne(&ctrlZCmd[0], NULL);
        if(ret!=0)
        {
            //ctrl+z执行失败再执行次
            Ec600sUartDataFlush();
        }
    }

    tick_start=OppTickCountGet();
    ret=Ec600sAtFmtCmdOne(&sendCmd[0], NULL, ATCMD_LEN, sock, len);
    if(0!=ret)
    {
        while(OppTickCountGet()-tick_start<sendCmd[0].waitTime)
        {
            ret=Ec600sDataRead(outbuf, NEUL_MAX_BUF_SIZE, 0, 10);
            if(ret>0)
            {
                if(0==sendCmd[0].atRspProc(outbuf,ret,NULL))
                {
                    break;
                }
            }
        }
    }
    //noted by wangtao
    //return Ec600sAtFmtCmdOne(&sendCmd[0], NULL, ATCMD_LEN, sock, len);
    return ret;
}

/**
@brief 发送数据
@param sock 套接字
@param data 数据内容
@param len  数据长度
@return 0.若连接已经建立，且发送成功,1.若连接已经建立，但是发送缓存已满,2.若连接未建立、 异常断开或者参数不正确
**/
int Ec600sAT_SendData(U8 data[], int len)
{
    return Ec600sAtFmtCmdOne(&dataCmd[0], NULL, len+ATCMD_LEN, data);
}

/**
@brief 发送16进制数据
@param sock 套接字
@param data 数据内容
@param len  数据长度
@return 0.若连接已经建立，且发送成功,1.若连接已经建立，但是发送缓存已满,2.若连接未建立、 异常断开或者参数不正确
**/
int Ec600sAT_QISENDEX(int sock,U8 data[],int len)
{
    char bufout[1024];//hex 512*2
    NeulBc28HexToStr(data, len, bufout);
    return Ec600sAtFmtCmdOne(&sendexCmd[0], NULL, len*2+ATCMD_LEN, sock, bufout);
}

/**
@brief 查询已发送字节数
@param sock 套接字
@param obuf 套接字发送结果
@return 0.成功,非0失败
**/
int Ec600sAT_QISEND0(int sock, char *obuf)
{
    ST_AT_EXE_OUT_DATA odata={0};
    odata.extract_data=(unsigned char*)obuf;

    return Ec600sAtFmtCmdOne(&send0Cmd[0], &odata, ATCMD_LEN, sock);
}

int Ec600sAT_QIRD0(int sock, char *obuf)
{
    ST_AT_EXE_OUT_DATA odata={0};
    odata.extract_data=(unsigned char*)obuf;

    return Ec600sAtFmtCmdOne(&qird0Cmd[0], &odata, ATCMD_LEN, sock);
}

int Ec600sAT_QIRD(int sock, char *obuf)
{
    ST_AT_EXE_OUT_DATA odata={0};
    odata.extract_data=(unsigned char*)obuf;

    return Ec600sAtFmtCmdOne(&qirdCmd[0], &odata, ATCMD_LEN, sock);
}

/**
@brief 入队列操作,去激活场景,URC[pdpdeact]调用
@param ctx 场景ID
@return 0.成功,非0失败
**/
int Ec600sAT_QIDEACT_QIN(int ctx)
{
    return Ec600sAtCmdQueueIn(&qideactCmd[0], ATCMD_LEN, ctx);
}

/**
@brief 入队列操作,关闭套接字
@param sock 套接字
@return 0.成功,非0失败
**/
int Ec600sAT_QICLOSE_QIN(int sock)
{
    return Ec600sAtCmdQueueIn(&closeCmd[0], ATCMD_LEN, sock);
}

/**
@brief ec600s tcpip模块初始化
@param 无
@return
**/
void Ec600sTcpipInit()
{
    MUTEX_CREATE(tcpipMux);
}

/**
@brief 查询场景状态
@param 无
@return场景状态
**/
EN_EC600S_CTX Ec600sCtxGet()
{
    EN_EC600S_CTX ctx;

    MUTEX_LOCK(tcpipMux,MUTEX_WAIT_ALWAYS);
    ctx=g_enCtxSt;
    MUTEX_UNLOCK(tcpipMux);
    return ctx;
}

/**
@brief 设置场景状态
@param ctx 场景状态
@return
**/
void Ec600sCtxSet(EN_EC600S_CTX ctx)
{
    MUTEX_LOCK(tcpipMux,MUTEX_WAIT_ALWAYS);
    g_enCtxSt=ctx;
    MUTEX_UNLOCK(tcpipMux);
}

/**
@brief TCPIP场景主处理函数
@param
@return
**/
int Ec600sCtxLoop()
{
    EN_EC600S_CTX ctx=Ec600sCtxGet();
    int ret;

    if(ctx==CTX_INIT)
    {
        printf("ctx init\r\n");
        if(0==Ec600sCtxInit())
        {
            Ec600sCtxSet(CTX_ACT);
        }
    }
    else if(ctx==CTX_ACT)
    {
        printf("ctx act\r\n");
        ret=Ec600sAT_QIACT(CTX_DEF);
        if(ret==0)
        {
            Ec600sCtxSet(CTX_READY);
        }
        //写失败或激活超时->重启模组
        else if(ret==-1||ret==-2)
        {
            Ec600sReset(EC600S_RST_CMD);
        }
        //激活失败->去激活
        else if(ret==-99)
        {
            Ec600sCtxSet(CTX_DEACT);
        }
    }
    else if(ctx==CTX_DEACT)
    {
        static U8 df=0;
        ret=Ec600sAT_QIDEACT(CTX_DEF);
        //错误码处理
        if(ret==0)
        {
            Ec600sCtxSet(CTX_INIT);
        }
        //写失败或去激活超时->复位模组
        else if(ret==-1||ret==-2)
        {
            Ec600sReset(EC600S_RST_CMD);
        }

        //激活失败,更新去激活失败次数
        if(ret==-99)
            df++;
        else
            df=0;
        //连续3次激活失败复位模组
        if(df>=CTX_DEACTS)
        {
            Ec600sReset(EC600S_RST_CMD);
            df=0;
        }
    }
    else if(ctx==CTX_READY)
    {

    }
    return 0;
}

int Ec600sSockHasDataSet(int s, int has)
{
    MUTEX_LOCK(tcpipMux,MUTEX_WAIT_ALWAYS);
    g_iSockHasData[s]=has;
    MUTEX_UNLOCK(tcpipMux);
    return 0;
}

int Ec600sSockHasDataGet(int s)
{
    int has;
    MUTEX_LOCK(tcpipMux,MUTEX_WAIT_ALWAYS);
    has=g_iSockHasData[s];
    MUTEX_UNLOCK(tcpipMux);
    return has;
}

/**
@brief 缓存模式下拆分套接字数据
@param
@return
**/
int Ec600sSockSzDataSplit(int s, U8 *data, int length)
{
    int j;
    int len;

    if(length<=3)
    {
        Ec600sSockUrcCallback(s,data,length);
    }
    else
    {
        for(j=0;j<length-3;)
        {
            if(data[j]==0x03&&data[j+3]==0x78)
            {
                len=ntohs(*(U16 *)&data[j+1])+3;
                Ec600sDataDump(&data[j], len);
                Ec600sSockUrcCallback(s,&data[j],len);
                j+=len;
            }
            else
            {
                j++;
            }
        }
    }
    return 0;
}

/**
@brief 缓存模式下读取套接字数据
@param
@return
**/
int Ec600sReadLoop()
{
    int i;
    ST_QIRD q;
    ST_QIRD0 q0;
    int ret;

    for(i=0;i<SOCK_MAX;i++)
    {
        if(Ec600sSockHasDataGet(i)>0)
        {
            while(1)
            {
                ret=Ec600sAT_QIRD0(i, (char*)&q0);
                if(q0.unread_length==0)
                {
                    break;
                }
                ret=Ec600sAT_QIRD(i, (char*)&q);
                if(0==ret)
                {
                    if(g_iSockDataSplit)
                    {
                        Ec600sSockSzDataSplit(i,q.data,q.len);
                    }
                    else
                    {
                        Ec600sSockUrcCallback(i,q.data,q.len);
                    }
                }
            }
            Ec600sSockHasDataSet(i,0);
        }
    }
    return 0;
}
/**
@brief 打开套接字失败处理函数
@param s 套接字
@param flags 0.套接字打开成功,1.套接字打开失败
@return
**/
int Ec600sQIPENFail(int s,int flags)
{
    static U8 num=0;

    if(flags==0)
    {
        num=0;
        return 0;
    }

    if(++num>=QIOPENTS)
    {
        Ec600sCtxSet(CTX_DEACT);
        num=0;
    }
    else
    {
        Ec600sSockStSet(s, SS_DISCONNECTING);
    }
    return 0;
}

/**
@brief 打开套接字超时处理函数
@param flags 0.倒计时中... 1.开始超时倒计时计算 2.打开套接字成功关闭开始倒计时 3.打开套接字失败关闭开始倒计时
@return
**/
int Ec600sQIOPENTo(int s, int flags)
{
    static U32 tick[SOCK_MAX]={0};
    static U8 proc[SOCK_MAX]={1};//0.倒计时中 1.倒计时完成
    static int init=0;

    if(!init)
    {
        memset(proc,1,sizeof(proc));
        init=1;
    }

    if(proc[s]==1)
        return 1;

    //开始超时倒计时计算
    if(flags==1)
    {
        tick[s]=0;
        proc[s]=0;
    }
    //打开套接字成功关闭开始倒计时
    else if(flags==2)
    {
        Ec600sQIPENFail(s,0);
        proc[s]=1;
        return 0;
    }
    //打开套接字失败关闭开始倒计时
    else if(flags==3)
    {
        Ec600sQIPENFail(s,1);
        proc[s]=1;
        return 0;
    }


    if(tick[s]==0)
        tick[s]=OppTickCountGet();

    if(OppTickCountGet()-tick[s]>QIOPENTO)
    {
        Ec600sQIPENFail(s,1);
        tick[s]=0;
        proc[s]=1;
    }

    return 0;
}

/**
@brief EC600S OPEN超时主处理函数
@param
@return
**/
int Ec600sQIOPENToLoop()
{
    int i;

    for(i=0;i<SOCK_MAX;i++)
    {
        Ec600sQIOPENTo(i,0);
    }
    return 0;
}

/**
@brief TCP ACK超时处理函数,被Ec600sDataSend调用
@param s 套接字
@param flags 0.等待确认ACK消息,s无效 1.设置套接字,重新开始确认ACK消息, 2.关闭ACK倒计时
@return
**/
int Ec600sTcpAckTo(int s, int flags)
{
    int ret;
    ST_QISEND0 q;
    static U32 tick[SOCK_MAX]={0};
    static U32 cnt[SOCK_MAX]={0};
    static U8 proc[SOCK_MAX]={1};
    static int init=0;

    if(!init)
    {
        memset(proc,1,sizeof(proc));
        init=1;
    }
    //计时处理完毕
    if(proc[s]==1)
        return 1;

    //flags=1重新开始计时处理
    if(flags==1)
    {
        tick[s]=0;
        cnt[s]=0;
        proc[s]=0;
    }
    else if(flags==2)
    {
        proc[s]=1;
        return 0;
    }

    if(tick[s]==0)
        tick[s]=OppTickCountGet();

    if(OppTickCountGet()-tick[s]>ACKTO)
    {
        ret=Ec600sAT_QISEND0(s,(char *)&q);
        if(ret!=0)
        {
            cnt[s]++;
            tick[s]=0;
            return 2;
        }
        //已经接受到ACK消息
        if(q.unack==0)
        {
            cnt[s]=0;
            proc[s]=1;
        }
        else
        {
            cnt[s]++;
        }

        tick[s]=0;
    }

    if(cnt[s]>=ACKTS)
    {
        Ec600sSockStSet(s, SS_DISCONNECTING);
        proc[s]=1;
    }
    return 0;
}

/**
@brief EC600S TCPIP ACK确认主处理函数
@param
@return
**/
int Ec600sTcpAckToLoop()
{
    int i;

    for(i=0;i<SOCK_MAX;i++)
    {
        Ec600sTcpAckTo(i,0);
    }
    return 0;
}

/**
@brief EC600S TCPIP主处理函数
@param
@return
**/
int Ec600sTcpipLoop()
{
    Ec600sCtxLoop();
    Ec600sQIOPENToLoop();
    Ec600sTcpAckToLoop();
    Ec600sReadLoop();
    return 0;
}


